﻿/************************************************************************

   Extended Silverlight Toolkit

   Copyright (C) 2010-2012 Xceed Software Inc.

   This program is provided to you under the terms of the Microsoft Public
   License (Ms-PL) as published at http://extendedsilverlight.codeplex.com/license

   Please purchase a commercial version of this toolkit if you are using
   it in a commercial product. The commercial versions support the project,
   and also include more features for each control, priority support,
   source code, updates, removed watermark, and a proprietary license.

   Visit http://xceed.com and follow @datagrid on Twitter.

  **********************************************************************/

using System;
using System.Collections.Generic;
using Xceed.Silverlight.Data.Stats;

namespace Xceed.Silverlight.Data
{
  internal class SyncToAsyncEnumerator<T> : AsyncEnumerator<T>
  {
    private static readonly Guid CountCallId = DataUtils.CreateCallId();
    private static readonly Guid GroupCountCallId = DataUtils.CreateCallId();
    private static readonly Guid GetStatValueCallId = DataUtils.CreateCallId();
    private static readonly Guid JumpMoveAndFetchCallId = DataUtils.CreateCallId();

    public SyncToAsyncEnumerator( ISyncEnumerator<T> synchronizedChild )
    {
      if( synchronizedChild == null )
        throw new ArgumentNullException( "synchronizedChild" );

      m_child = synchronizedChild;
      m_child.DataChanged += new EventHandler<DataChangedEventArgs>( ChildDataChanged );
    }

    public override bool IsFullySynchronized
    {
      get
      {
        return true;
      }
    }

    public ISyncEnumerator<T> ChildEnumerator
    {
      get
      {
        return m_child;
      }
    }

    private void ChildDataChanged( object sender, DataChangedEventArgs args )
    {
      this.RaiseDataChanged( args );
    }

    public override IAsyncResult BeginCount( CountParameters parameters, AsyncCallback userCallback, object asyncState )
    {
      CountResult result = m_child.Count( parameters );
      AsyncResult asyncResult = new AsyncResult( SyncToAsyncEnumerator<T>.CountCallId, null, null );

      asyncResult.StartSync( result );

      return asyncResult;
    }

    public override CountResult EndCount( IAsyncResult asyncResult )
    {
      asyncResult.ValidateCallEnd( SyncToAsyncEnumerator<T>.CountCallId );

      return asyncResult.GetCallResult<CountResult>();
    }

    public override IAsyncResult BeginGroupCount( CountParameters parameters, AsyncCallback userCallback, object asyncState )
    {
      GroupCountResult result = m_child.GroupCount( parameters );
      AsyncResult asyncResult = new AsyncResult( SyncToAsyncEnumerator<T>.GroupCountCallId, null, null );

      asyncResult.StartSync( result );

      return asyncResult;
    }

    public override GroupCountResult EndGroupCount( IAsyncResult asyncResult )
    {
      asyncResult.ValidateCallEnd( SyncToAsyncEnumerator<T>.GroupCountCallId );

      return asyncResult.GetCallResult<GroupCountResult>();
    }

    public override IAsyncResult BeginGetStatValues( StatParameters parameters, AsyncCallback userCallback, object asyncState )
    {
      StatResults result = m_child.GetStatValues( parameters );
      AsyncResult asyncResult = new AsyncResult( SyncToAsyncEnumerator<T>.GetStatValueCallId, null, null );

      asyncResult.StartSync( result );

      return asyncResult;
    }

    public override StatResults EndGetStatValues( IAsyncResult asyncResult )
    {
      asyncResult.ValidateCallEnd( SyncToAsyncEnumerator<T>.GetStatValueCallId );

      return asyncResult.GetCallResult<StatResults>();
    }

    public override JumpMoveAndFetchAsyncResult BeginJumpMoveAndFetch(
      JumpMoveAndFetchParameters parameters, 
      AsyncCallback userCallback, 
      object asyncState )
    {
      Nullable<long> actualMove;
      ICollection<T> data;
      SourcePosition endPosition;
      RelativeOffset endPositionOffset;
      EstimateInt64 totalCount;

      bool ret = m_child.JumpMoveAndFetch(
                   parameters,
                   out actualMove,
                   out data,
                   out endPosition,
                   out endPositionOffset,
                   out totalCount );

      JumpMoveAndFetchAsyncResult asyncResult = new JumpMoveAndFetchAsyncResult( 
                                                      SyncToAsyncEnumerator<T>.JumpMoveAndFetchCallId, 
                                                      userCallback, 
                                                      asyncState,
                                                      parameters );
      asyncResult.StartSync(
        new JumpMoveAndFetchResult<T>(
          asyncResult,
          actualMove,
          data,
          ret,
          endPosition,
          endPositionOffset,
          totalCount ) );

      return asyncResult;
    }

    public override JumpMoveAndFetchResult<T> EndJumpMoveAndFetch( JumpMoveAndFetchAsyncResult jumpMoveAndFetchAsyncResult )
    {
      jumpMoveAndFetchAsyncResult.ValidateCallEnd( SyncToAsyncEnumerator<T>.JumpMoveAndFetchCallId );

      return jumpMoveAndFetchAsyncResult.GetCallResult<JumpMoveAndFetchResult<T>>();
    }

    protected override IEnumerable<DataSourceChangedEventArgs> TransformDataSourceChangedEventArgs( 
      DataSourceContext context, 
      DataSourceChangedEventArgs e )
    {
      throw new NotSupportedException();
    }

    #region IDisposable Member

    protected override void Dispose( bool disposing )
    {
      base.Dispose( disposing );

      if( disposing )
      {
        if( m_child != null )
        {
          m_child.DataChanged -= ChildDataChanged;
          m_child.Dispose();
        }
      }
    }

    #endregion

    #region Private Fields

    private ISyncEnumerator<T> m_child;

    #endregion
  }
}
